<!-- HTML header for doxygen 1.8.3.1-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.3.1"/>
<title>Sifteo SDK: Asset Workflow</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
  $(document).ready(function() { searchBox.OnSelectItem(0); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen-style-overrides.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<center>
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Sifteo SDK" src="sdk_logo.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">
   &#160;<span id="projectnumber">v1.0.0</span>
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
</center>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.3.1 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
  <div id="navrow1" class="tabs">
    <ul class="tablist">
      <li><a href="index.html"><span>Home</span></a></li>
      <li class="current"><a href="pages.html"><span>Guides</span></a></li>
      <li><a href="modules.html"><span>Modules</span></a></li>
      <li><a href="annotated.html"><span>Reference</span></a></li>
      <li>
        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="Search" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
          </span>
        </div>
      </li>
    </ul>
  </div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Classes</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Namespaces</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark">&#160;</span>Functions</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark">&#160;</span>Variables</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(5)"><span class="SelectionMark">&#160;</span>Typedefs</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(6)"><span class="SelectionMark">&#160;</span>Enumerations</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(7)"><span class="SelectionMark">&#160;</span>Enumerator</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(8)"><span class="SelectionMark">&#160;</span>Groups</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(9)"><span class="SelectionMark">&#160;</span>Pages</a></div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Asset Workflow </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>How to prepare, proof and deploy visual and audio assets</p>
<p><b>stir</b> is a tool that formats your visual and audio assets to the compact formats used on Sifteo Cubes. It accepts configuration files written in <a href="http://www.lua.org">Lua</a>, and generates C++ code that should be built into your project.</p>
<p>Proofs of your image assets are also generated, formatted as HTML documents, so you can easily inspect them in your browser after the formatting process.</p>
<h1>Asset Images</h1>
<p>Let's look at a basic assets.lua config dealing with images only:</p>
<div class="fragment"><div class="line">GameAssets = group{}</div>
<div class="line"></div>
<div class="line">Background = image{<span class="stringliteral">&quot;stars-bg.png&quot;</span>, quality=9.85}</div>
<div class="line">Star = image{<span class="stringliteral">&quot;star-8.png&quot;</span>, pinned=<span class="keyword">true</span>, width=8, height=8}</div>
<div class="line">Font = image{<span class="stringliteral">&quot;font-8x16.png&quot;</span>, pinned=<span class="keyword">true</span>, width=8, height=16}</div>
</div><!-- fragment --><p>The <b>group</b> element specifies that a <a class="el" href="struct_sifteo_1_1_asset_group.html" title="A bundle of compressed tile data, for use by AssetImages.">Sifteo::AssetGroup</a> named <code>GameAssets</code> should be created. This group contains all the <code>image</code> entries that follow it, until another <code>group</code> is declared. You can also explicitly specify the group that an <code>image</code> belongs to by adding <code>group=MyGroupName</code> within the <code>image</code> element.</p>
<p>All images in a single <em>group</em> are compressed together, and form a bundle of compressed asset data which is loaded to the Sifteo Cubes in one piece. For more information on AssetGroups, see <a class="el" href="asset_memory.html">Asset Memory Management</a>.</p>
<p>Each <b>image</b> element specifies that an AssetImage should be generated. Given no other details, a plain <a class="el" href="struct_sifteo_1_1_asset_image.html" title="Any kind of asset image, as defined in your stir script.">Sifteo::AssetImage</a> will be generated, as in the case of <b>Background</b> above. By adding <code>pinned=true</code>, a <a class="el" href="struct_sifteo_1_1_pinned_asset_image.html" title="An AssetImage in which all tiles are stored sequentially in memory.">Sifteo::PinnedAssetImage</a> is created. Pinned assets are required for sprites, since the Sifteo platform requires all tiles in a sprite to be sequential.</p>
<p>By default, images are compressed to save room in your game's binary. However, if you need random access to your image data from within your game, you can specify <code>flat=1</code> within your <code>image</code> element, and <b>stir</b> will create a <a class="el" href="struct_sifteo_1_1_flat_asset_image.html" title="An AssetImage in which all tile indices are stored in a flat array, without any additional compressio...">Sifteo::FlatAssetImage</a> instead - a larger, uncompressed version of your image. For example: <code>Background = image{"stars-bg.png", flat=true}</code></p>
<h2>Color</h2>
<p>No guarantees are made about the specific RGB color space for source images, since the LCD on each Sifteo Cube is not color-calibrated and colors can vary significantly with changes in viewing angle.</p>
<p>Stir does not perform any colorspace conversion other than rounding each pixel to the nearest 16-bit RGB565 color. However, the compression process needs to evaluate the perceptibility of every individual lossy operation that could be performed, to decide which transforms would be too lossy given the current quality level. These perceptual comparisons are made in the linear CIELAB color space, after converting from an approximated sRGB colorspace with a single gamma of 2.2.</p>
<h2>Quality</h2>
<p>Images are compressed more or less aggressively based on their <code>quality</code> parameter. Quality can be any real number from 1 to 10, with 10 meaning lossless, and lower values giving <b>stir</b> more freedom to compress.</p>
<p>All images within a <a class="el" href="struct_sifteo_1_1_asset_group.html" title="A bundle of compressed tile data, for use by AssetImages.">Sifteo::AssetGroup</a> can share tiles, and if <b>stir</b> determines that tiles within different images are similar enough, it can create a single tile to be shared by the 2 images, reducing the overall size of your application's installation. Of course, if the quality setting is too high, <b>stir</b> cannot take these liberties and your application will be larger as a result.</p>
<p>Compression is a very important part of keeping your asset budget under control. Dial down the quality for your images as much as you can stand and applications will be smaller, asset installation times will be shorter, and the world will be a better place.</p>
<p>Quality is continuously variable. Don't be shy about using a quality value like 9.998 if that's what looks best for your assets. Avoid using a quality of 10 unless it's vital that the assets are completely lossless. Lossless compression will often result in many tiles which have no visible differences.</p>
<h2>Frames</h2>
<p>If you omit <code>width</code> and <code>height</code> attributes for your image elements, <b>stir</b> will default to creating AssetImages with the native width and height of your source image, in a single frame.</p>
<p>Animations consisting of multiple frames should lay out each frame contiguously in the source image. You can then specify <code>width</code> or <code>height</code> to indicate the size of a frame within your image. In this case, <b>stir</b> will divide your image into a grid of appropriately sized frames, and its <code>frames</code> attribute will be calculated accordingly from left to right, top to bottom.</p>
<dl class="section note"><dt>Note</dt><dd>If you're creating a long animation which may have many duplicated frames in it, stir will automatically factor out these duplicated frames assuming the asset is not marked as <code>flat</code> or <code>pinned</code>. The <em>Dictionary Uniform Block (DUB)</em> codec operates on blocks of up to 8x8 tiles within each frame. If any 8x8 tile blocks are identical, they will all be represented by the same data in memory.</dd></dl>
<h2>Image Option Summary</h2>
<table class="doxtable">
<tr>
<th>Option </th><th>Meaning</th></tr>
<tr>
<td><code>quality=N</code> </td><td>Set the quality of this image to <code>N</code>, where N is a number between 1 and 10 </td></tr>
<tr>
<td><code>pinned=true</code> </td><td>Create a <a class="el" href="struct_sifteo_1_1_pinned_asset_image.html" title="An AssetImage in which all tiles are stored sequentially in memory.">Sifteo::PinnedAssetImage</a> </td></tr>
<tr>
<td><code>flat=true</code> </td><td>Create a <a class="el" href="struct_sifteo_1_1_flat_asset_image.html" title="An AssetImage in which all tile indices are stored in a flat array, without any additional compressio...">Sifteo::FlatAssetImage</a> </td></tr>
<tr>
<td><code>width=8</code> </td><td>Specify the width of a frame in your image, defaults to source image's native width. </td></tr>
<tr>
<td><code>height=16</code> </td><td>Specify the height of a frame of your image, defaults to source image's native height. </td></tr>
<tr>
<td><code>group=MyGroup</code> </td><td>Specify that this image is a member of the <code>group</code> element <code>MyGroup</code> </td></tr>
</table>
<h2>Asset Image Lists</h2>
<p>It is occasionally desirable to export images as an array.</p>
<div class="fragment"><div class="line">Environments = group{}</div>
<div class="line"></div>
<div class="line">TileSets = { image{<span class="stringliteral">&quot;desert.png&quot;</span>}, image{<span class="stringliteral">&quot;ocean.png&quot;</span>}, image{<span class="stringliteral">&quot;castle.png&quot;</span>} }</div>
</div><!-- fragment --><p>Image Lists must contain only images, or else they are ignored. Furthermore, the images must be homogeneous: you may not interleave pinned, flat and ordinary assets in the same list.</p>
<p>Asset Image Lists are just a way of grouping together several distinct AssetImage instances. This can be handy when you have several images which are related, but may have different dimensions or compression formats, or when each image already contains multiple frames.</p>
<p>Note that this syntax is distinct from the following, which creates a single <a class="el" href="struct_sifteo_1_1_asset_image.html" title="Any kind of asset image, as defined in your stir script.">Sifteo::AssetImage</a> with two frames by passing an array of PNG filenames to the image constructor:</p>
<div class="fragment"><div class="line">Sprites = group{}</div>
<div class="line"></div>
<div class="line">PlayerSprite = image{ { <span class="stringliteral">&quot;player-sitting.png&quot;</span>, <span class="stringliteral">&quot;player-standing.png&quot;</span>}, pinned=<span class="keyword">true</span> }</div>
</div><!-- fragment --><dl class="section note"><dt>Note</dt><dd>If you have the choice between using a single Asset Image with multiple frames, instead of an Asset Image List, the single Asset Image can be more efficient.</dd></dl>
<h1><a class="anchor" id="asset_audio"></a>
Audio</h1>
<p>The Sifteo audio system supports both sample and tracker module playback. Tracker audio is great for longer, sequenced audio, like background music. Samples are typically used for shorter assets, like sound effects, or for audio that is not easily sequenced, like speech.</p>
<p>If you haven't already, see <a class="el" href="audio.html">Audio</a> for details of the Sifteo audio system.</p>
<h2>Samples</h2>
<p>Here's an assets.lua snippet that creates two samples:</p>
<div class="fragment"><div class="line">Click = sound{ <span class="stringliteral">&quot;click.wav&quot;</span> }</div>
<div class="line">Bloop = sound{ <span class="stringliteral">&quot;bloop.wav&quot;</span>, encode=<span class="stringliteral">&quot;pcm&quot;</span> }</div>
</div><!-- fragment --><p>Each <b>sound</b> element specifies that a <a class="el" href="struct_sifteo_1_1_asset_audio.html" title="An audio asset, using any supported compression codec.">Sifteo::AssetAudio</a> object should be generated, which can be played by a <a class="el" href="struct_sifteo_1_1_audio_channel.html" title="One mixer channel, capable of playing AudioAssets.">Sifteo::AudioChannel</a>.</p>
<p><code>stir</code> treats <code>sound</code> files whose name ends in <code>.wav</code> as WAV files, which are widely supported in most audio editing and authoring environments. <code>stir</code> helps ensure that your WAV files are prepared correctly:</p>
<ul>
<li>data format for samples is <b>signed 16-bit</b></li>
<li>sample rate is no higher than the system max of <b>16kHz</b></li>
</ul>
<p>If you need to force a custom sample rate you can do so with the <code>sample_rate</code> option, like so:</p>
<div class="fragment"><div class="line">Bleep = sound{ <span class="stringliteral">&quot;bleep.raw&quot;</span>, sample_rate=8000 }</div>
</div><!-- fragment --><h3>Sample Rate</h3>
<p><code>stir</code> will detect the sample rate of your WAV files, and configure your AudioAsset to play at its native sample rate by default. You can also manipulate the rate of playback at runtime using <a class="el" href="struct_sifteo_1_1_audio_channel.html#a075fb9a950a3a4aab9fe421f359731b8" title="Sets the speed of this channel, in samples per second.">Sifteo::AudioChannel::setSpeed()</a>.</p>
<p>Lower sample rates will typically result in lower quality audio, but can also introduce storage savings - if the quality is acceptable and you're strapped for storage space, it can be a good tradeoff.</p>
<p><code>stir</code> rejects WAV files with sample rates higher than the system max of 16kHz - there's no use fetching more data than can be rendered by the audio device.</p>
<h3>Compression</h3>
<p>The default encoding for audio data in external storage is ADPCM, which compresses your source audio to 25% of its original size. To specify that your sample be stored uncompressed, add the <code>encode="pcm"</code> option to your <code>sound</code> object, as in the <code>Bloop</code> entry above.</p>
<h2>Tracker</h2>
<p>Here's an assets.lua containing two modules:</p>
<div class="fragment"><div class="line">Bubbles = tracker{<span class="stringliteral">&quot;bubbles.xm&quot;</span>}</div>
<div class="line">Slumberjack = tracker{<span class="stringliteral">&quot;slumberjack.xm&quot;</span>, loop=<span class="keyword">false</span>}</div>
</div><!-- fragment --><p>Each <b>tracker</b> element specifies that a <a class="el" href="struct_sifteo_1_1_asset_tracker.html" title="A Tracker module, converted from XM format by stir">Sifteo::AssetTracker</a> module should be generated, which can be played by a <a class="el" href="struct_sifteo_1_1_audio_tracker.html" title="Playback interface for Tracker modules.">Sifteo::AudioTracker</a>.</p>
<p>By default, tracker modules loop using the restart point defined in the XM file. Modules play only once if the restart point is not valid. You may specify the <code>loop=false</code> option to forcibly disable looping.</p>
<h1>stir Options</h1>
<p><b>stir</b> provides several options to configure its execution. These options are integrated into the default Makefiles that ship with the SDK, but you may wish to integrate <b>stir</b> into your workflow in other ways.</p>
<table class="doxtable">
<tr>
<th>Option </th><th>Meaning</th></tr>
<tr>
<td><code>-h</code> </td><td>Show a help message and exit </td></tr>
<tr>
<td><code>-v</code> </td><td>Enable verbose output </td></tr>
<tr>
<td><code>-o &lt;myproof&gt;.html</code> </td><td>Writes an HTML image proof to <code>&lt;myproof&gt;.html</code> - open this up in your web browser </td></tr>
<tr>
<td><code>-o &lt;assets.gen&gt;.cpp</code> </td><td>Generates C++ source data for your assets to <code>&lt;assets.gen&gt;.cpp</code> - include this file in your build </td></tr>
<tr>
<td><code>-o &lt;assets.gen&gt;.h</code> </td><td>Generates C++ header data for your assets to <code>&lt;assets.gen&gt;.h</code> - include this file in your build </td></tr>
<tr>
<td><code>VAR=VALUE</code> </td><td>Define a Lua script variable, prior to parsing the script </td></tr>
</table>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.3.1-->
<!-- start footer part -->
    <hr class="footer"/>
    <address class="footer">
        <p><a href="http://sifteo.com">Sifteo</a> SDK v1.0.0 <small>(see <a href="https://developers.sifteo.com/sifteosdk">all versions</a>)</small></p>
        <p>Last updated Wed Mar 27 2013, by <a href="http://www.stack.nl/~dimitri/doxygen">Doxygen</a></p>
    </address>
</body>
</html>
